package com.hup.joystick.presenter;

import com.hup.joystick.model.BootOption;
import com.hup.joystick.model.FunctionConfig;
import com.hup.joystick.model.MainConfig;
import com.hup.joystick.model.MainConfig.FunctionRecord;
import com.hup.joystick.model.joystick.AutoConnectConfig;
import com.hup.joystick.mvp.MainMvp.MainPresenter;
import com.hup.joystick.service.joystick.AutoConnectListener;
import com.hup.joystick.service.joystick.JoystickService;
import com.hup.joystick.view.main.AppTray;
import com.hup.joystick.view.main.MainWindow;
import com.hup.utils.commons.exception.AppCommonException;
import com.hup.utils.commons.hardware.SystemUtil;
import com.hup.utils.commons.io.BaseConfig;
import com.hup.utils.commons.io.FileUtil;
import com.hup.utils.commons.start.SimpleExitHandler;
import com.hup.utils.commons.start.SingletonAppManager;
import com.hup.utils.commons.start.SingletonAppManager.SingletonAppHandler;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.commons.start.StartupInfo;
import com.hup.utils.swing.frame.BaseFrame;
import com.hup.utils.swing.frame.SingletonWindowHelper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Objects;

/**
 * @author hugan
 * @date 2020/10/15
 */
@Log4j2
@Component
public class MainPresenterImpl implements MainPresenter {

    private final JoystickService joystickService;
    private final int appPort;
    private final SingletonAppManager singletonAppManager;
    private AppTray appTray;
    /**
     * 主界面; 未验证[仅在启动方法时,会被内存回收?]
     */
    @SuppressWarnings("FieldCanBeLocal")
    private MainWindow mainWindow;

    public MainPresenterImpl(JoystickService joystickService, @Value("${appPort}") String appPort) {
        try {
            this.appPort = Integer.parseInt(appPort);
            singletonAppManager = SingletonAppManager.doStart(new MySingletonAppHandler());
        } catch (Exception e) {
            throw new AppCommonException("application.properties的端口号异常[" + appPort + "]");
        }
        log.info("isAdmin={}, defaultCharset={}", SystemUtil.isAdmin(), Charset.defaultCharset());
        this.joystickService = joystickService;
        SpringContext.getBean(SimpleExitHandler.class).setExitAction(this::doExit);
    }

    @Override
    public void startUp(BootOption bootOption) throws Exception {
        log.debug("bootOption={}", bootOption);
        joystickService.initDirectInput();
        FileUtil.createDir(BaseConfig.Path.getBaseDir());
        appTray = new AppTray();
        appTray.doShow();
        mainWindow = new MainWindow();
        mainWindow.switchVisible(true);

        if (bootOption.hideWindow) mainWindow.switchVisible(false);
    }

    @Override
    public void doExit() {
        log.info("");
        //两个stop都要调用,且代码要按序,要等待线程
        joystickService.stopAutoConnect(true);
        joystickService.stopListenState(true);
        joystickService.doFree();
        singletonAppManager.doStop();
        appTray.doHide();
        System.exit(0);
    }

    @Override
    public void startAutoConnect(AutoConnectListener autoConnectListener) {
        joystickService.startAutoConnect(new AutoConnectConfig(), autoConnectListener);
    }

    @Override
    public void stopAutoConnect(boolean waitEndingThread) {
        joystickService.stopAutoConnect(waitEndingThread);
    }

    @Override
    public void buildFunctionConfig(MainConfig config) {
        //列出功能列表
        config.lstFunction.clear();
        ArrayList<FunctionConfig> lstTemp = FunctionConfig.getUserFunctions();

        //删除[无效,丢失]的配置,更新功能的enable属性(lstFunction中多余的,都是生效的),按序添加到config中
        int recordSize = config.lstFunctionRecord.size();
        config.lstFunctionRecord.removeIf(functionRecord -> {
            for (FunctionConfig function : lstTemp)
                if (Objects.equals(function.name, functionRecord.name)) {
                    function.enable = functionRecord.enable;
                    function.foundInRecord = true;
                    function.sortConfigFields();
                    config.lstFunction.add(function);
                    return false;
                }
            log.info("移除丢失配置:{}", functionRecord.name);
            return true;
        });
        boolean hadLost = recordSize != config.lstFunctionRecord.size();//record中有丢失的记录

        //把新配置添加到record中
        boolean hasNew = false;//有新配置(record中没有的)
        for (FunctionConfig function : lstTemp) {
            if (!function.foundInRecord) {
                function.sortConfigFields();
                config.lstFunction.add(function);
                config.lstFunctionRecord.add(new FunctionRecord(function.name));
                hasNew = true;
                log.info("新配置={}", function.name);
            }
        }
        //标准化文件路径
        for (FunctionConfig functionConfig : config.lstFunction) {
            ArrayList<String> lstApp = functionConfig.lstApp;
            for (int i = 0, lstAppSize = lstApp.size(); i < lstAppSize; i++)
                lstApp.set(i, FileUtil.normalize(lstApp.get(i)));
        }

        if (hadLost || hasNew) config.save();
    }

    @Override
    public void onWindowClosing(Class<? extends BaseFrame> clz) {
        SingletonWindowHelper.getWindow(MainWindow.class).onWindowClosing(clz);
    }

    private class MySingletonAppHandler implements SingletonAppHandler {
        @Override
        public int port() {
            return appPort;
        }

        @Override
        public String appTag() {
            return StartupInfo.getApplicationName();
        }

        @Override
        public void onAppReduplicateStart() {
            mainWindow.switchVisible(true);
        }

        @Override
        public String portSettingFileDesc() {
            return "config/application.properties的appPort";
        }
    }
}
